Namespace Utility

    ''' <summary>
    ''' Get the assembly information from a dll using AppDoamin.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class AsmInfoExplorer
        Inherits Object

        Private Const DNAME_DEFAULT As String = "DOMAIN"
        Private m_ap As AppDomain
        Private m_Title, m_Copyright, m_Description, m_Company, m_Product As String
        Private m_Version As Version
        Private m_refAsms As Dictionary(Of String, String)

        ''' <summary>
        ''' The title of the assembly.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Title() As String
            Get
                Return m_Title
            End Get
        End Property

        ''' <summary>
        ''' The copyright of the assembly.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Copyright() As String
            Get
                Return m_Copyright
            End Get
        End Property

        ''' <summary>
        ''' The description of the assembly.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Description() As String
            Get
                Return m_Description
            End Get
        End Property

        ''' <summary>
        ''' The company of the assembly.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Company() As String
            Get
                Return m_Company
            End Get
        End Property

        ''' <summary>
        ''' The product name of the assembly.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Product() As String
            Get
                Return m_Product
            End Get
        End Property

        ''' <summary>
        ''' The version of the assembly.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Version() As Version
            Get
                Return m_Version
            End Get
        End Property

        ''' <summary>
        ''' The string type version of the assembly.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property DisplayVersion() As String
            Get
                Return m_Version.Major & Common.Variants.DOT & m_Version.Minor & Common.Variants.DOT & m_Version.Build
            End Get
        End Property

        ''' <summary>
        ''' The referenced assemblies list of current assembly.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ReferenceAssemblies() As Dictionary(Of String, String)
            Get
                Return m_refAsms
            End Get
        End Property

        ''' <summary>
        ''' Create instance.
        ''' </summary>
        ''' <param name="asm">The assembly to load.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal asm As Reflection.Assembly)
            m_refAsms = New Dictionary(Of String, String)
            FillAsmInfo(asm)
        End Sub

        ''' <summary>
        ''' Create instance.
        ''' </summary>
        ''' <param name="sender">The object to load.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal sender As Object)
            m_refAsms = New Dictionary(Of String, String)
            FillAsmInfo(sender.GetType.Assembly)
        End Sub

        ''' <summary>
        ''' Create instance.
        ''' </summary>
        ''' <param name="Path">The path of dll file to load.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal Path As String)
            Dim al As AssemblyLoader
            m_refAsms = New Dictionary(Of String, String)
            If IO.File.Exists(Path) = True Then
                Try
                    al = CreateAssemblyLoaderInstanse()
                    al.LoadAssemblyFile(Path)
                    m_Title = al.Title
                    m_Copyright = al.Copyright
                    m_Description = al.Description
                    m_Company = al.Company
                    m_Product = al.Product
                    m_Version = al.Version
                Catch ex As Exception
                Finally
                    Unload()
                End Try
            Else
                Throw New IO.FileNotFoundException
            End If
        End Sub

        ''' <summary>
        ''' Get the random string by date and time used by AppDomain Name.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function Rnd() As String
            Return Now.Year & Now.Month & Now.Date & Now.Hour & Now.Minute & Now.Second & Now.Minute
        End Function

        ''' <summary>
        ''' Resolve event handler.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="args"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function OnResolveEventHandler(ByVal sender As Object, ByVal args As ResolveEventArgs) As System.Reflection.Assembly
            Dim MyAssembly As System.Reflection.Assembly = Nothing
            If args.Name = System.Reflection.Assembly.GetExecutingAssembly().FullName Then
                MyAssembly = System.Reflection.Assembly.LoadFrom(System.Reflection.Assembly.GetExecutingAssembly().Location)
            End If
            Return MyAssembly
        End Function

        ''' <summary>
        ''' Create the AppDomain by default name.
        ''' </summary>
        ''' <param name="DomainName">The AppDomain name.</param>
        ''' <returns>AssemblyLoader object.</returns>
        ''' <remarks></remarks>
        Private Function CreateAssemblyLoaderInstanse(Optional ByVal DomainName As String = "") As AssemblyLoader
            Dim objh As System.Runtime.Remoting.ObjectHandle
            Dim obj As Object
            Dim al As AssemblyLoader
            Try
                If DomainName.Trim = "" Then
                    DomainName = DNAME_DEFAULT & Rnd()
                End If
                AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf OnResolveEventHandler
                m_ap = AppDomain.CreateDomain(DomainName)
                objh = m_ap.CreateInstanceFrom(System.Reflection.Assembly.GetExecutingAssembly().Location, GetType(AssemblyLoader).FullName)
                obj = objh.Unwrap()
                al = CType(obj, AssemblyLoader)
            Catch ex As Exception
                al = Nothing
            End Try
            Return al
        End Function

        ''' <summary>
        ''' Unload the assembly and release the dll file access.
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub Unload()
            RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf OnResolveEventHandler
            If Not m_ap Is Nothing Then
                AppDomain.Unload(m_ap)
            End If
        End Sub

        ''' <summary>
        ''' Fill the assembly infomation into the vars.
        ''' </summary>
        ''' <param name="asm">Assembly object.</param>
        ''' <remarks></remarks>
        Private Sub FillAsmInfo(ByVal asm As Reflection.Assembly)
            Dim attribs() As Object
            Dim attrib As Object
            Dim refasm As Reflection.AssemblyName
            If Not asm Is Nothing Then
                'Load assembly info from assemblyinfo.vb
                attribs = asm.GetCustomAttributes(True)
                m_Version = asm.GetName.Version
                For Each attrib In attribs
                    If TypeOf attrib Is Reflection.AssemblyTitleAttribute Then
                        m_Title = attrib.Title
                    ElseIf TypeOf attrib Is Reflection.AssemblyDescriptionAttribute Then
                        m_Description = attrib.Description
                    ElseIf TypeOf attrib Is Reflection.AssemblyCopyrightAttribute Then
                        m_Copyright = attrib.Copyright
                    ElseIf TypeOf attrib Is Reflection.AssemblyCompanyAttribute Then
                        m_Company = attrib.Company
                    ElseIf TypeOf attrib Is Reflection.AssemblyProductAttribute Then
                        m_Product = attrib.Product
                    End If
                Next
                'Load reference assemblies
                For Each refasm In asm.GetReferencedAssemblies
                    If m_refAsms.ContainsKey(refasm.Name) = False Then
                        m_refAsms.Add(refasm.Name, refasm.Version.ToString)
                    End If
                Next
            End If
        End Sub

#Region " Assembly Loader Class (With AppDomain) "

        ''' <summary>
        ''' Assembly loader class with AppDomain.
        ''' </summary>
        ''' <remarks></remarks>
        Private NotInheritable Class AssemblyLoader
            Inherits MarshalByRefObject

            Private m_Asm As Reflection.Assembly
            Private m_Title, m_Copyright, m_Description, m_Company, m_Product As String
            Private m_Version As Version

            ''' <summary>
            ''' The title of the assembly.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property Title() As String
                Get
                    Return m_Title
                End Get
            End Property

            ''' <summary>
            ''' The copyright of the assembly.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property Copyright() As String
                Get
                    Return m_Copyright
                End Get
            End Property

            ''' <summary>
            ''' The description of the assembly.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property Description() As String
                Get
                    Return m_Description
                End Get
            End Property

            ''' <summary>
            ''' The company of the assembly.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property Company() As String
                Get
                    Return m_Company
                End Get
            End Property

            ''' <summary>
            ''' The product name of the assembly.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property Product() As String
                Get
                    Return m_Product
                End Get
            End Property

            ''' <summary>
            ''' The version of the assembly.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property Version() As Version
                Get
                    Return m_Version
                End Get
            End Property

            ''' <summary>
            ''' Load the assembly object from dll path.
            ''' </summary>
            ''' <param name="Path">The dll file full name.</param>
            ''' <remarks></remarks>
            Public Sub LoadAssemblyFile(ByVal Path As String)
                If IO.File.Exists(Path) = True Then
                    m_Asm = Reflection.Assembly.LoadFrom(Path)
                    FillAsmInfo()
                End If
            End Sub

            ''' <summary>
            ''' Fill the assembly infomation into the vars.
            ''' </summary>
            ''' <remarks></remarks>
            Private Sub FillAsmInfo()
                Dim attribs() As Object
                Dim attrib As Object
                If Not m_Asm Is Nothing Then
                    attribs = m_Asm.GetCustomAttributes(True)
                    m_Version = m_Asm.GetName.Version
                    For Each attrib In attribs
                        If TypeOf attrib Is Reflection.AssemblyTitleAttribute Then
                            m_Title = attrib.Title
                        ElseIf TypeOf attrib Is Reflection.AssemblyDescriptionAttribute Then
                            m_Description = attrib.Description
                        ElseIf TypeOf attrib Is Reflection.AssemblyCopyrightAttribute Then
                            m_Copyright = attrib.Copyright
                        ElseIf TypeOf attrib Is Reflection.AssemblyCompanyAttribute Then
                            m_Company = attrib.Company
                        ElseIf TypeOf attrib Is Reflection.AssemblyProductAttribute Then
                            m_Product = attrib.Product
                        End If
                    Next
                End If
            End Sub

        End Class

#End Region

    End Class

End Namespace
